#pragma once
#include <zGraphicsConfig.hpp>
#include "RT_Ray.hpp"
#include "../Graphics/AABB.hpp"

namespace zzz {
// interior node of a k-d tree
struct ZGRAPHICS_CLASS RT_KdNode {
	enum SAxis{AXIS_X = 0, AXIS_Y, AXIS_Z};
	SAxis splitFlag; // decide split axis
	float split; //decide split plane position
	int left, right, parent ; //l/r child or parent index in the RT_KdNode List
								// if left/ right is a negative interger,then its child is a leaf(use abs to index)
	unsigned int nElems;
};

// leaf of a k-d tree
struct ZGRAPHICS_CLASS RT_KdLeaf {
	zuint nElems;
	vector<int> elems;
	int prim;  //bounding box for the leaf's triangle
	int parent; //parent index in Node List
};

// axis aligned accelebrated data struct
class ZGRAPHICS_CLASS RT_KdTree {
public:
  RT_KdTree();
  void Clear();

	//description : user interface , see member func buildTree
	bool Build(const vector<Vector3f> &points, const vector<Vector3i> &faces);

	//description : test intersect for a given ray, return the hit point's properties (pos,normal,texcoord)
	bool Intersect(RT_Ray &ray, int &f, Vector3f &bary);

	//description : only test if a given ray intersects the scene ,return true is hits any mesh
	bool DoesIntersect(RT_Ray &ray) ;

	//vector<RT_Triangle> mTriangleList;
  vector<Vector3i> faces_;
  vector<Vector3f> points_;

private:
  // build a kdTree based on current vertexes and indexes recursively
  // building strategy : minimize the cost(node) = Cost on traversal + (1 - be)(PB * NB * ti + PA * NA * ti)
  //	where be is a bonus for one-side empty choice , PB,PA is the probabilities of left and right ,NB, NA is the number of tris of left and right.
  int BuildTree(const AABB3f &nodeBounds, vector<int> &mTris, int numTris ,int depth);
	int CreateLeaf(const AABB3f& leafBounds, const vector<int> &mTris, int numTris); 
	bool NodeIntersect(int index, const AABB3f &nodeBounds, RT_Ray &ray, int &f, Vector3f &bary);
	bool NodeIntersectP(int index, const AABB3f &nodeBounds, RT_Ray &ray);
		
	bool LeafIntersect(int index, RT_Ray &ray, int &f, Vector3f &bary);
	bool LeafIntersectP(int index, RT_Ray &ray);

  AABB3f GetTriangleAABB(int t) const;
  int TriangleIntersectPlaneAxis(int t, float pos, int axis) const;
  bool TriangleIntersect(int t, const RT_Ray &ray, Vector3f &bary, float &hitDist) const;
  bool TriangleDoesIntersect(int t, const RT_Ray &ray) const;
	// keep scene's mesh content in
	vector<AABB3f> mPrimList;
	// keep interior nodes
	vector<RT_KdNode> mNodes;
	vector<RT_KdLeaf> mLeafs;

	AABB3f mBounds;

	int root;  //root node index;

	float mbe ; // bonus param of be ,in the range of [0, 1]
	float mCostTt;  // cost on traverse the interior node and decide ray partition method, i set it as 1.0f
	float mCostTi;  // cost on intersect with a elem ,say a triangle, i set is a 80.0f; 

	// when the interior node's depth exceed the max depth, or it contains no more than minElems elems, it should become a RT_KdLeaf
	int maxDepth; 
	int minElems;

	int mCurNodeIndex;
	int mCurLeafIndex;

};
}
